package com.geline.mybatisplus.handler.impl;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.geline.cloud.util.DynamicSqlUtil;
import com.geline.mybatisplus.handler.ForeignKeyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author mx
 * @date 2025/9/27
 */
@Slf4j
public class DefaultForeignKeyHandler implements ForeignKeyHandler {

    private JdbcTemplate jdbcTemplate;

    public DefaultForeignKeyHandler(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Serializable getMainKey(Object entity, String mainTable, String foreignKey) {
        BeanMap map = BeanMap.create(entity);
        if(foreignKey.contains(",")){
            String[] keys = foreignKey.split(",");
            boolean isExistNull = false;
            for (String key : keys){
                Object value = map.get(StrUtil.toCamelCase(key));
                if(value==null){
                    isExistNull = true;
                    break;
                }
            }
            if(isExistNull){
                //存在null属性
                TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
                String currentNamespace = tableInfo.getCurrentNamespace();
                //com.xxxx.HeaderInformationMapper
                Class<BaseMapper> mainMapperClass = ClassUtil.loadClass(currentNamespace);
                BaseMapper mainMapper = SpringUtil.getBean(mainMapperClass);
                Serializable idValue = getIdValue(entity);
                entity = mainMapper.selectById(idValue);
                map = BeanMap.create(entity);
            }

            List<Object> values = new ArrayList<>();
            for (String key : keys){
                Object value = map.get(StrUtil.toCamelCase(key));
                values.add(value);
            }
            String mainKey = StrUtil.join(":", values);
            if(mainKey.contains("null")){
                log.warn("mainKey is null: {} = {}", foreignKey, mainKey);
                log.warn("entity11: {} = {}", entity.getClass(), JSONUtil.toJsonStr(entity));
            }
            return mainKey;
        }else {
            Serializable mainIdValue = (Serializable) BeanMap.create(entity).get(StrUtil.toCamelCase(foreignKey));
            if (StrUtil.isBlankIfStr(mainIdValue)){
                //如果Entity外键为null，重新取Entity对象再获取外键值
                TableInfo info = TableInfoHelper.getTableInfo(entity.getClass());
                Class<BaseMapper> mapperClass = ClassUtil.loadClass(info.getCurrentNamespace());
                BaseMapper baseMapper = SpringUtil.getBean(mapperClass);
                Serializable idValue = getIdValue(entity);
                entity = baseMapper.selectById(idValue);
                mainIdValue = (Serializable) BeanMap.create(entity).get(StrUtil.toCamelCase(foreignKey));
            }
            if (mainIdValue == null){
                log.warn("mainIdValue is null: {} = {}", foreignKey, mainIdValue);
                log.warn("entity22: {} = {}", entity.getClass(), JSONUtil.toJsonStr(entity));
            }
            return mainIdValue;
        }
    }

    @Override
    public Object getMainEntity(Object entity, String mainTable, String foreignKey) {
        log.debug(">>> mainTable={}, foreignKey={}", mainTable, foreignKey);
        TableInfo tableInfo = TableInfoHelper.getTableInfo(mainTable);
        if(foreignKey.contains(",")){
            Class<?> entityType = tableInfo.getEntityType();
            StringBuffer sb = new StringBuffer();
            sb.append("select * from "+mainTable+" where 1=1");
            String[] keys = foreignKey.split(",");
            for (String key : keys){
                sb.append(String.format(" and %s=#{%s}", StrUtil.toUnderlineCase(key), StrUtil.toCamelCase(key)));
            }
            String sql = DynamicSqlUtil.parseSQL(sb.toString(), BeanMap.create(entity));
            if(sql.contains("#{") || sql.contains("${")){
                //存在null属性；重新取Entity对象
                TableInfo subInfo = TableInfoHelper.getTableInfo(entity.getClass());
                String currentNamespace = subInfo.getCurrentNamespace();
                Class<BaseMapper> subMapperClass = ClassUtil.loadClass(currentNamespace);
                BaseMapper subMapper = SpringUtil.getBean(subMapperClass);
                Serializable idValue = getIdValue(entity);
                entity = subMapper.selectById(idValue);
            }
            sql = DynamicSqlUtil.parseSQL(sb.toString(), BeanMap.create(entity));
            if(sql.contains("#{") || sql.contains("${")){
                //存在null属性
                throw new RuntimeException("error sql : "+sql);
            }
            try {
                Object object = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(entityType));
                return object;
            }catch (Exception e){
                log.warn("no data by sql : {}", sql);
            }
            return null;
        }else {
            Serializable mainIdValue = (Serializable) BeanMap.create(entity).get(StrUtil.toCamelCase(foreignKey));
            if (StrUtil.isBlankIfStr(mainIdValue)){
                //如果Entity外键为null，重新取Entity对象再获取外键值
                TableInfo info = TableInfoHelper.getTableInfo(entity.getClass());
                Class<BaseMapper> mapperClass = ClassUtil.loadClass(info.getCurrentNamespace());
                BaseMapper baseMapper = SpringUtil.getBean(mapperClass);
                Serializable idValue = getIdValue(entity);
                entity = baseMapper.selectById(idValue);
                mainIdValue = (Serializable) BeanMap.create(entity).get(StrUtil.toCamelCase(foreignKey));
            }
            if (mainIdValue != null){
                TableInfo mainInfo = TableInfoHelper.getTableInfo(mainTable);
                String currentNamespace = mainInfo.getCurrentNamespace();
                Class<BaseMapper> mapperClass = ClassUtil.loadClass(currentNamespace);
                log.debug(">>> currentNamespace={}, {}", mainIdValue, currentNamespace);
                BaseMapper mainMapper = SpringUtil.getBean(mapperClass);
                //com.xxxx.HeaderInformationMapper
                Object mainEntity = mainMapper.selectById(mainIdValue);
                log.debug(">>> mainEntity={}, {}", mainIdValue, JSONUtil.toJsonStr(mainEntity));
                return mainEntity;
            }
            return null;
        }
    }

    private Serializable getIdValue(Object entity) {
        Serializable idValue = null;
        if (entity != null) {
            idValue = (Serializable) BeanMap.create(entity).get("id");
            if(idValue!=null){
                return idValue;
            }
        }
        Field[] declaredFields = entity.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId != null) {
                idValue = (Serializable) BeanMap.create(entity).get(field.getName());
                break;
            }
        }
        return idValue;
    }
}
